home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 2 / Apprentice-Release2.iso / Tools / Languages / GCC 1.37.1r14 / usr / gcc-1.37.1r14 / object oriented files / CBrowseResDoc.cp < prev    next >
Encoding:
Text File  |  1993-08-04  |  18.7 KB  |  691 lines  |  [TEXT/KAHL]

  1. /******************************************************************************
  2.  CBrowseResDoc.c
  3.  
  4.         
  5.     SUPERCLASS = CDocument
  6.     
  7.     Copyright © 1991 Symantec Corporation. All rights reserved.
  8.     
  9.     CBrowseResDoc is a document class for browsing resource files. It can
  10.     display the contents of existing resource files, but not modify their
  11.     contents or create new resource files.
  12.     It provides examples of
  13.         - a multi-window document
  14.         - using the Table and Dialog classes
  15.         - using resource files. However, resources are handled in a pretty
  16.           minimalist way. Applications that create, edit, and save resource
  17.           files will need to do more.
  18.           
  19.     When you open a resource file, CBrowseResDoc creates a window with a
  20.     CScrollPane and a CResTypePane. The CResTypePane displays a scrolling
  21.     list of the resource types in the file. Any types that CBrowseResDoc
  22.     can display are shown in bold. 
  23.     
  24.     For any resource type, double-clicking opens a new window showing
  25.     a list of all the resources of that type. The window is implemented
  26.     by creating an instance of CResBrowser or an appropriate subclass.
  27.     ResBrowser will display a list of resource types, but cannot open
  28.     individual resources. Subclasses of ResBrowser, such as CDLOGBrowser
  29.     can create windows for viewing individual resources. They may also
  30.     elect to display the list of resources in a custom view by overriding
  31.     CResBrowser::BuildWindow.
  32.     
  33.     The other new subclasses used to implement CBrowseResDoc are:
  34.         CResTypePane, CResListPane, CResBrowser, and CDLOGBrowser.
  35.     
  36.  
  37.  ******************************************************************************/
  38.  
  39. #include "CBrowseResDoc.h"
  40. #include <CDesktop.h>
  41. #include "ResourceStructs.h"
  42. #include <CScrollPane.h>
  43. #include <CDecorator.h>
  44. #include "CResTypePane.h"
  45. #include <CResFile.h>
  46. #include "CDLOGBrowser.h"
  47. #include "CDRVRBrowser.h"
  48. #include <TCLUtilities.h>
  49. #include <CArray.h>
  50. #include <CWindow.h>
  51.  
  52. #define        cmdOpenType            1050    // open window on a resource type
  53. #define        cmdOpenResource        1051    // open window on a resource
  54. #define        kResBrowseWind        1025        // 'WIND' resource ID 
  55.  
  56. extern     CDesktop     *gDesktop;
  57. extern    CDecorator    *gDecorator;
  58. extern    CBartender    *gBartender;    /* The menu handling object */
  59.  
  60. /******************************************************************************
  61.  IBrowseResDoc
  62.  
  63.      The initialization method. Any new instance variables defined by this
  64.      class should be initialized. You must always call the superclass's 
  65.      initialization method as early as possible, but first null out any
  66.      pointer references in the event that there is a failure during
  67.      initialization.
  68.  
  69. ******************************************************************************/
  70.  
  71. void CBrowseResDoc::IBrowseResDoc( CApplication *aSupervisor, Boolean printable)
  72. {
  73.     itsResTypes = NULL;
  74.     itsTypePane = NULL;
  75.     
  76.     CDocument::IDocument( aSupervisor, printable);
  77.     
  78.     //    Create a new, empty array for the resource type information
  79.     
  80.     itsResTypes = new CArray;
  81.     
  82.     // The argument to IArray is the size of each element in this array
  83.     
  84.     itsResTypes->IArray( sizeof( tResTypeInfo));
  85. }
  86.  
  87. /******************************************************************************
  88.  NewFile
  89.  
  90.      Does not create new files. Any document that creates new files should
  91.      override NewFile and create and show a new, untitled window.
  92.      
  93. ******************************************************************************/
  94.  
  95. void CBrowseResDoc::NewFile(void)
  96. {
  97.  
  98. }
  99.  
  100. /******************************************************************************
  101.  OpenFile
  102.  
  103.      Open the existing file given in macSFReply. This requires creating a
  104.      new File object, opening the file, creating a window, and installing the
  105.      data in the window.
  106.      
  107. ******************************************************************************/
  108.  
  109. void CBrowseResDoc::OpenFile( SFReply *macSFReply)
  110. {
  111.     CResFile    *resFile;
  112.     short        savedRes;
  113.     
  114.     /*
  115.      *    Failure handling:
  116.      *        The only objects created within the activation of this
  117.      *        method are those already known to the standard TCL classes,
  118.      *        e.g. itsFile, itsWindow, subviews of itsWindow, etc. Before
  119.      *        calling OpenFile, CDemoApp has posted an exception handler.
  120.      *        If an exception occurs, CDemoApp will call Dispose for this
  121.      *        document, which in turn will dispose of the file, the window
  122.      *        all all its subviews. Therefore, no exception handler is
  123.      *        needed for this method.
  124.      */
  125.      
  126.         // We use the TCL class CResFile to represent our resource file.
  127.     
  128.     resFile = new CResFile;
  129.     
  130.         // assign the file to CDocument::itsFile so CDocument knows about the file.
  131.         
  132.     itsFile = resFile;
  133.     
  134.         // call its initialization method
  135.     
  136.     resFile->IResFile();
  137.     
  138.         // fill in the file information
  139.         
  140.     resFile->SFSpecify( macSFReply);
  141.     
  142.         // If the file has no resource fork, we'll just display
  143.         // an empty window. Since we don't modify the file, there's
  144.         // no point in creating a resource fork.
  145.     
  146.     if (resFile->HasResFork())
  147.     {
  148.         //     Save the current resource file, because opening
  149.         //     a resource file makes it the current file. Since
  150.         //     we don't know anything about the resources in this
  151.         //     file we don't want to take the chance that it has
  152.         //    resources that could conflict with our application
  153.         //  or system resources. Therefore we will always save
  154.         //    and restore the current resource file when dealing
  155.         //    with this file.
  156.         
  157.         savedRes = CurResFile();
  158.  
  159.         // open the file
  160.         
  161.         resFile->Open( fsRdWrPerm);
  162.         
  163.         // restore the old resource file
  164.         
  165.         UseResFile( savedRes);
  166.         
  167.         // Build a list of all types in this file
  168.         
  169.         BuildTypeList();
  170.     }
  171.  
  172.     // create the resource type window
  173.     
  174.     BuildMainWindow();
  175.     
  176.     // Ask gDecorator to place this window. StaggerWindow places the
  177.     // window, but does not change its size.
  178.     
  179.     gDecorator->StaggerWindow( itsWindow);
  180.     
  181.     // Set the window title to the file name
  182.     
  183.     itsWindow->SetTitle( macSFReply->fName);
  184.     
  185.     // Finally, show the window
  186.     
  187.     itsWindow->Select();
  188. }
  189.  
  190. /******************************************************************************
  191.  DoCommand
  192.  
  193.      The cmdOpenType command is generated by a double-click in the type list.
  194. ******************************************************************************/
  195.  
  196. void CBrowseResDoc::DoCommand( long aCommand)
  197. {
  198.     switch( aCommand)
  199.     {
  200.         case cmdOpenType:
  201.             OpenTypeWindow();
  202.             break;
  203.             
  204.         //    Always call inherited::DoCommand for commands you don't handle
  205.         
  206.         default:
  207.             inherited::DoCommand( aCommand);
  208.             break;
  209.     }
  210. }
  211.  
  212. /******************************************************************************
  213.  Dispose
  214.  
  215.      Release all memory used by this object.
  216. ******************************************************************************/
  217.  
  218. void CBrowseResDoc::Dispose( void)
  219. {
  220.     //    We only need to dispose of instance variables declared by
  221.     //    this subclass that our superclass wouldn't automatically
  222.     //    dispose of. Therefore we ignore itsFile, itsWindow, etc,
  223.     //  and only dispose of itsResTypes.
  224.     
  225.     ForgetObject( itsResTypes);
  226.     inherited::Dispose();
  227. }
  228.  
  229. /******************************************************************************
  230.  CanOpenType
  231.  
  232.      Returns true if we will be able to open a window for a resource
  233.      of the given type.
  234. ******************************************************************************/
  235.  
  236. Boolean CBrowseResDoc::CanOpenType( ResType aResType)
  237. {
  238.     switch(aResType)
  239.         {
  240.         case 'DLOG':
  241.         case 'DRVR':
  242.         return 1;
  243.         }
  244.     return 0;
  245. }
  246.  
  247. /******************************************************************************
  248.  BuildMainWindow
  249.  
  250.      Creates the resource type window and all its subviews.
  251. ******************************************************************************/
  252.  
  253. void CBrowseResDoc::BuildMainWindow( void)
  254. {
  255.     CScrollPane    *scrollPane;
  256.     
  257.     // Create a window object and initialize it from a WIND resource
  258.     
  259.     itsWindow = new CWindow;
  260.     itsWindow->IWindow( kResBrowseWind, FALSE, gDesktop, this);
  261.     
  262.     // Create scroll pane with a vertical scroll bar and a size box.
  263.     
  264.     scrollPane = new CScrollPane;
  265.     scrollPane->IScrollPane( itsWindow, this, 0, 0, 0, 0,
  266.                     sizELASTIC, sizELASTIC, FALSE, TRUE, TRUE);
  267.                     
  268.     // Fit the scroll pane to the window
  269.     
  270.     scrollPane->FitToEnclFrame( TRUE, TRUE);
  271.  
  272.     // Create a CResTypePane for displaying the list of resource types
  273.     
  274.     itsTypePane = new CResTypePane;
  275.     itsTypePane->IResTypePane( scrollPane, this, 0, 0, 0, 0,
  276.                     sizELASTIC, sizELASTIC);
  277.     itsTypePane->FitToEnclosure( TRUE, TRUE);
  278.     
  279.     // Link itsTypePane to itsResTypes.
  280.     
  281.     itsTypePane->SetArray( itsResTypes, FALSE);
  282.     
  283.     // Double-clicking in itsTypePane will send the cmdOpenType command
  284.     // to this document.
  285.     
  286.     itsTypePane->SetDblClickCmd( cmdOpenType);
  287.     
  288.     // Set the selection behavior for the type list so only one row
  289.     // is selected at a time.
  290.     
  291.     itsTypePane->SetSelectionFlags( selOnlyOne);
  292.     
  293.     // Set itsTypePane as the panorama for the scroll pane.
  294.  
  295.     scrollPane->InstallPanorama( itsTypePane);
  296.     
  297.     // itsGopher is the object that will be the first to receive
  298.     // menu commands, keystrokes, and idle time for this document.
  299.     
  300.     // itsMainPane is the pane that is printed if the document is
  301.     // printable.
  302.     
  303.     itsGopher = itsMainPane = itsTypePane;
  304.     
  305. }
  306.  
  307. /******************************************************************************
  308.  BuildTypeList
  309.  
  310.      Build a list of all the resource types in the file
  311.      
  312. ******************************************************************************/
  313.  
  314. void CBrowseResDoc::BuildTypeList( void)
  315. {
  316.     short            savedResFile = CurResFile();
  317.     short            currIndex, numTypes;
  318.     tResTypeInfo    typeInfo;
  319.     
  320.     /*
  321.      *    Failure Handling:
  322.      *        Its possible for a failure to occur during this method.
  323.      *        For example, we could run out of memory while trying
  324.      *        to insert into itsResTypes. Rather than exiting
  325.      *        this method with the current resource file set to
  326.      *        itsFile, and itsResTypes in a partially consistent
  327.      *        state, we post an exception handler to cleanup before
  328.      *        propagating the exception.
  329.      */
  330.     
  331.     TRY
  332.     {
  333.         // Make itsFile the current resource file
  334.         
  335.         ((CResFile*)itsFile)->MakeCurrent();
  336.         
  337.         // Get the number of types in the resource file.
  338.         // Then for each type, fill in a tResTypInfo struct
  339.         // and insert it into itsResTypes array.
  340.         
  341.         numTypes = Count1Types();
  342.         for( currIndex = 1; currIndex <= numTypes; currIndex++)
  343.         {
  344.             // what is the type?
  345.             
  346.             Get1IndType( &typeInfo.type, currIndex);
  347.             
  348.             if (ResError() != noErr)
  349.                 break;
  350.                 
  351.             // NULL the window field. It stores a reference
  352.             // to a Director for the window for that type.
  353.     
  354.             typeInfo.window = NULL;
  355.             
  356.             // can we open a window on resources of this type?
  357.             
  358.             typeInfo.editable = CanOpenType( typeInfo.type);
  359.             
  360.             // insert it to the array
  361.             
  362.             itsResTypes->InsertAtIndex( &typeInfo, currIndex);
  363.         }
  364.         // restore the original resource file
  365.         
  366.         UseResFile( savedResFile);
  367.     }
  368.     CATCH
  369.     {
  370.         // Something failed here. Restore the resource, empty the
  371.         // array, then allow the exception to propagate.
  372.         
  373.         UseResFile( savedResFile);
  374.         itsResTypes->Resize( 0);
  375.     }
  376.     ENDTRY;
  377. }
  378.  
  379. /******************************************************************************
  380.  OpenTypeWindow
  381.  
  382.      Opens a window for the given resource type. Called in response to
  383.      the cmdOpenType command.
  384. ******************************************************************************/
  385.  
  386. void CBrowseResDoc::OpenTypeWindow( void)
  387. {
  388.     Cell            selectedCell;
  389.     tResTypeInfo    typeInfo;
  390.     
  391.     // Get the tResTypeInfo struct corresponding to
  392.     // the selected cell. If a window already exists
  393.     // for this type, then bring it to the front, otherwise
  394.     // call MakeTypeBrowser to make a new window.
  395.     
  396.     selectedCell.h = selectedCell.v = 0;
  397.     if (itsTypePane->GetSelect( TRUE, &selectedCell))
  398.     {
  399.         itsResTypes->GetItem( &typeInfo, selectedCell.v + 1);
  400.         if (typeInfo.window)
  401.         {
  402.             // typeInfo.window is a director responsible
  403.             // for displaying the given type. Select its
  404.             // window.
  405.             
  406.             typeInfo.window->GetWindow()->Select();
  407.         }
  408.         else
  409.         {
  410.             // No director exists. Create a new one, then
  411.             // store the reference back into the array so
  412.             // we'll know the window already exists later on.
  413.             
  414.             typeInfo.window = MakeTypeBrowser( typeInfo.type);
  415.             itsResTypes->SetItem( &typeInfo, selectedCell.v + 1);
  416.         }
  417.     }
  418. }
  419.  
  420. /******************************************************************************
  421.  MakeTypeBrowser
  422.  
  423.      Create a browser for the given resource type. For the types
  424.      we know about, like DLOG, we create a special subclass of CResBrowser.
  425.      Otherwise we create a CResBrowser, which supplies the default behavior.
  426.      
  427. ******************************************************************************/
  428.  
  429. CResBrowser *CBrowseResDoc::MakeTypeBrowser( ResType aType)
  430. {
  431.     CArray         *resList = NULL;
  432.     CResBrowser *director = NULL;
  433.     
  434.     /*
  435.      *    Failure Handling:
  436.      *        If this method fails, that means we couldn't
  437.      *        successfully open the new browser. If
  438.      *        resList or director were allocated, then
  439.      *        free them before allowing the exception to propagate.
  440.      */
  441.     
  442.     TRY
  443.     {
  444.         resList = BuildResourceList( aType);
  445.         
  446.         switch(aType)
  447.             {
  448.             case 'DLOG':
  449.                 {
  450.                 CDLOGBrowser *dlgDir = new CDLOGBrowser;
  451.                 director = dlgDir;
  452.                 dlgDir->IDLOGBrowser( this, resList);
  453.                 break;
  454.                 }
  455.             case 'DRVR':
  456.                 {
  457.                 CDRVRBrowser *dlgDir = new CDRVRBrowser;
  458.                 director = dlgDir;
  459.                 dlgDir->IDRVRBrowser( this, resList);
  460.                 break;
  461.                 }
  462.             default:
  463.                 {    
  464.                 director = new CResBrowser;
  465.                 director->IResBrowser( this, aType, resList);
  466.                 break;
  467.                 }
  468.         }
  469.     }
  470.     CATCH
  471.     {
  472.         // Both resList and director were initialized to NULL at the
  473.         // start of this method. If either is not NULL now, then
  474.         // we know it was in fact created. If director was
  475.         // created, then its initialization method was called,
  476.         // and ownership of the list was passed of to it. If it wasn't
  477.         // created, then we must dispose of the list.
  478.         
  479.         if (!director)
  480.             ForgetObject( resList);
  481.         ForgetObject( director);
  482.     }
  483.     ENDTRY;
  484.     
  485.     return director;
  486. }
  487.  
  488. /******************************************************************************
  489.  BuildResourceList
  490.  
  491.      Build an array of tResourceInfo structs, containing information 
  492.      about all the resources in the file of the given type.
  493.      
  494. ******************************************************************************/
  495.  
  496. CArray *CBrowseResDoc::BuildResourceList( ResType aType)
  497. {
  498.     CArray    *resList = NULL;
  499.     short    savedRes = CurResFile();
  500.     short    currIndex, numRes;
  501.     tResourceInfo    resInfo;
  502.     ResType            type;
  503.     Boolean            savedAlloc = kAllocCantFail;
  504.     
  505.     /*
  506.      *    Failure Handling:
  507.      *        If an exception occurs, we want to dispose of the
  508.      *        array, because it was not completely created.
  509.      *        Also, we ensure that the resource file is restored.
  510.      */
  511.     
  512.     TRY
  513.     {
  514.             // Create an array whose elements are tResourceInfo
  515.             
  516.         resList = new CArray;
  517.         resList->IArray( sizeof( tResourceInfo));
  518.         
  519.             // None of the resources have a window yet
  520.         
  521.         resInfo.window = NULL;
  522.         
  523.             // make the resource file current
  524.         
  525.         ((CResFile*)itsFile)->MakeCurrent();
  526.         
  527.             // For each resource of the given type, fill in a
  528.             // tResourceInfo struct and insert it to the array
  529.  
  530.         numRes = Count1Resources( aType);
  531.         for( currIndex = 1; currIndex <= numRes; currIndex++)
  532.         {
  533.         
  534.                 //     Before attempting to load the resource,
  535.                 //    tell the TCL that this is a non-critical
  536.                 //    attempt to allocate memory that is allowed
  537.                 //    to fail.
  538.                 
  539.             savedAlloc = SetAllocation( kAllocCanFail);
  540.             
  541.             resInfo.resource = Get1IndResource( aType, currIndex);
  542.             
  543.             savedAlloc = SetAllocation( savedAlloc);
  544.             
  545.                 // Raise an exception if we couldn't load the
  546.                 // resource.
  547.             
  548.             FailNIL(resInfo.resource);
  549.             
  550.                 // Get its size, ID, and name
  551.     
  552.             resInfo.size = GetHandleSize( resInfo.resource);
  553.             GetResInfo( resInfo.resource, &resInfo.ID, &type,
  554.                         resInfo.name);
  555.                         
  556.                 // allow the resource to be purged. We'll explicitly
  557.                 // load it if we need it later.
  558.             
  559.             HPurge( resInfo.resource);    
  560.             
  561.                 // put the info into the array.
  562.                     
  563.             resList->InsertAtIndex( &resInfo, currIndex);
  564.         }        
  565.     }
  566.     CATCH
  567.     {
  568.         // Something failed. Restore the resource file, free the list
  569.         // and propagate the exception.
  570.         
  571.         UseResFile( savedRes);
  572.         ForgetObject( resList);
  573.     }
  574.     ENDTRY;
  575.  
  576.     // We were successful :-). Restore the original resource
  577.     // file, and return the array.
  578.     
  579.     UseResFile( savedRes);
  580.     return resList;
  581.  
  582. }
  583.  
  584. /******************************************************************************
  585.  RemoveDirector {OVERRIDE}
  586.  
  587.      This is called when one of our subdirectors, i.e. one of the
  588.      resource browsers was closed. We override in order to remove
  589.      the reference to the window from the reference to it we
  590.      stored in itsResTypes.
  591.      
  592. ******************************************************************************/
  593.  
  594.     static int FindTypeDirector( CResBrowser *typeDirector, tResTypeInfo *typeInfo)
  595.     {
  596.         if (typeInfo->window == typeDirector)
  597.         {
  598.             typeInfo->window = NULL;
  599.             return 0;
  600.         }
  601.         return 1;
  602.     }
  603.  
  604. void CBrowseResDoc::RemoveDirector( CDirector *aDirector)
  605. {
  606.     // Search the array, looking for the entry corresponding to
  607.     // aDirector. Since the search function clears the entry
  608.     // there is nothing else to do.
  609.     
  610.     if (itsResTypes)
  611.         itsResTypes->Search( aDirector, (CompareFunc) FindTypeDirector);
  612.     
  613.     inherited::RemoveDirector( aDirector);
  614. }
  615.  
  616. void CBrowseResDoc::AddType( Handle theHandle, ResType newtype, Str255 newname)
  617. {
  618.     short            savedResFile = CurResFile();
  619.     TRY
  620.     {
  621.         Str255    DRVRname;
  622.         int numRes,currIndex,i = 0;
  623.         int maxid = 1;
  624.         int newid = 0;
  625.         tResTypeInfo typeInfo;
  626.         BlockMove(newname+1, DRVRname+2, *newname);
  627.         *DRVRname = 1+*newname;
  628.         DRVRname[1] = 0;
  629.         // Make itsFile the current resource file
  630.         ((CResFile*)itsFile)->MakeCurrent();
  631.         numRes = Count1Resources( newtype);
  632.         for( currIndex = 1; currIndex <= numRes; currIndex++)
  633.             {
  634.             ResType         type;
  635.             tResourceInfo    resInfo;
  636.             Boolean         savedAlloc = SetAllocation( kAllocCanFail);            
  637.             resInfo.resource = Get1IndResource( newtype, currIndex);
  638.             savedAlloc = SetAllocation( savedAlloc);
  639.             FailNIL(resInfo.resource);
  640.             resInfo.size = GetHandleSize( resInfo.resource);
  641.             GetResInfo( resInfo.resource, &resInfo.ID, &type, resInfo.name);
  642.             if (EqualString(DRVRname, resInfo.name, TRUE, TRUE))
  643.                 {
  644.                 newid = resInfo.ID;
  645.                 RmveResource(resInfo.resource);
  646.                 AddResource(theHandle,newtype,newid,DRVRname);
  647.                 }
  648.             else HPurge( resInfo.resource);    
  649.             if (maxid <= resInfo.ID) maxid = resInfo.ID+1;
  650.             }
  651.         if (!newid) 
  652.             {
  653.             newid = maxid;
  654.             AddResource(theHandle,newtype,newid,DRVRname);
  655.             }
  656.         FailOSErr (ResError());
  657.         dirty = TRUE;
  658.         UseResFile( savedResFile);
  659.         if (numRes) i = itsResTypes->GetNumItems();
  660.         while ( i )
  661.             {
  662.             itsResTypes->GetItem( &typeInfo, i);    
  663.             if (typeInfo.type == newtype) i = 0;
  664.             else i--;
  665.             }
  666.         if ((typeInfo.type != newtype) || !numRes)
  667.             {
  668.             typeInfo.window = NULL;
  669.             typeInfo.type = newtype;
  670.             typeInfo.editable = CanOpenType( typeInfo.type);
  671.             itsResTypes->InsertAtIndex( &typeInfo, 1);
  672.             itsTypePane->SetArray( itsResTypes, FALSE);
  673.             itsWindow->Select();
  674.             }
  675.         else if (typeInfo.window) typeInfo.window->Close(FALSE);
  676.     }
  677.     CATCH
  678.     {
  679.         UseResFile( savedResFile);
  680.     }
  681.     ENDTRY;
  682. }
  683.  
  684. Boolean CBrowseResDoc::DoSave(void)
  685.     {
  686.     ((CResFile *)itsFile)->Update();            
  687.     dirty = FALSE;                    /* Document is no longer dirty        */
  688.     gBartender->DisableCmd(cmdSave);
  689.     return(TRUE);                    /* Save was successful                */
  690.     }
  691.